/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tewi.jeeunit.config;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Formatter;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.tewi.jeeunit.utils.FileUtils;

/**
 * Wypakowuje konfigurację serwera aplikacyjnego z archiwum
 * @author Marcin Kwapisz
 */
public class ExtractServerConfiguration implements ServerConfigurationStrategy {

    /**
     * Logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ExtractServerConfiguration.class);

    /**
     * Wypakowuje katalog i wszystkie pliki się w nim znajdujące z podanego pliku jar/zip
     * @param file plik archiwum z którego będzie wypakowywany katalog z plikami
     * @param srcDirectory katalog źródłowy znajdujący się w archiwum
     * @param destDirectory katalog docelowy w systemie plików do którego zostanie skopiowany katalog źródłowy
     * @throws IOException nieprawidłowa nazwa katalogu, nie można utworzyć katalogu docelowego bądź problem z kopiowaniem plików
     */
    @Override
    public final void prepareConfiguration(final File file, final String srcDirectory, final String destDirectory) throws IOException {
        //Przetwórz File na JarFile
        final JarFile jarFile = new JarFile(file);

        StringBuilder builder = new StringBuilder();
        builder.delete(0, builder.length());

        //dodaj do nazwy katalogu separator ścieżki (tak jest nazwany katalog w archiwum)
        // Nie można użyć tej metody gdyż w archiuwm jest zawsze używany / a nie File.separator
//        String sourceDir=FileUtils.appendFileSeparator(srcDirectory);
        String sourceDir;
        if (!srcDirectory.endsWith("/")) {
            sourceDir = srcDirectory + "/"; //File.separator;
        } else {
            sourceDir = srcDirectory;
        }

        //Sprawdź czy w archiwum jest podany katalog
        JarEntry entry = jarFile.getJarEntry(sourceDir);
        if (entry == null || !entry.isDirectory()) {
            builder = new StringBuilder();
            Formatter formatter = new Formatter(builder);
            throw new IOException(formatter.format("Directory %1s not found in an archive %2s", sourceDir, jarFile.getName()).toString());
        }

        //załóż docelowy katalog w systemie plików
        final String targetDir = FileUtils.joinPaths(destDirectory, sourceDir);
        File targetDirFile = FileUtils.createDirectory(targetDir);
        //po utworzeniu katalogu docelowgo wróć do początkowego jego ustawienia. Pliki w archiwum już zawierają część ścieżki
        targetDirFile = new File(FileUtils.joinPaths(destDirectory, File.separator));

        //dla każdego pliku w archiwum który nie jest katalogiem - skopiuj go
        //do okreslonej lokalizacji
        Enumeration<JarEntry> jarEntries = jarFile.entries();

        File targetFile;
        while (jarEntries.hasMoreElements()) {
            entry = jarEntries.nextElement();
            //skopiuj wszystkie pliki pomiń te które istnieją
            if (!entry.isDirectory() && entry.getName().startsWith(sourceDir)) {
                //entry.getName() zawiera nazwę katalogu
                targetFile = FileUtils.joinPaths(targetDirFile, entry.getName());
                if (targetFile.exists()) {
                    LOGGER.debug("File {} already exists - deleting", targetFile);
                    targetFile.delete();
//                    continue;
                }
                LOGGER.debug("Coping {}", targetFile);
                InputStream is = new BufferedInputStream(jarFile.getInputStream(entry));
                OutputStream os = new BufferedOutputStream(new FileOutputStream(targetFile));
                byte[] buffer = new byte[4096];

                for (;;) {
                    int bytesRead = is.read(buffer);
                    if (bytesRead < 0) {
                        break;
                    }
                    os.write(buffer, 0, bytesRead);
                }
                //wyczyść bufor zapisu i zamknij strumienie
                os.flush();
                os.close();
                is.close();
            }
        }
    }
}
